package com.leantech.android.browser.ui.browser

import android.annotation.SuppressLint
import android.app.Dialog
import android.app.SearchManager
import android.content.Intent
import android.content.pm.ActivityInfo
import android.os.Bundle
import android.webkit.CookieManager
import android.webkit.GeolocationPermissions
import android.webkit.WebStorage
import android.webkit.WebViewDatabase
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.cscj.android.repository.settings.model.SettingConstants
import com.cscj.android.utils.LOG
import com.cscj.android.utils.UrlUtils
import com.lean.android.ad.core.AdLoaders
import com.lean.android.ad.core.PrivacyDialogBlockChain
import com.lean.android.ad.core.VipDialogBlockChain
import com.lean.android.ad.workflow.WorkFlows
import com.leantech.android.browser.HotSplashAdState
import com.leantech.android.browser.R
import com.leantech.android.browser.browser.BrowserDelegate
import com.leantech.android.browser.browser.BrowserTab
import com.leantech.android.browser.browser.TabController
import com.leantech.android.browser.databinding.ActivityBrowserBinding
import com.leantech.android.browser.dialog.BottomSheetDialogHelper
import com.leantech.android.browser.dialog.CheckboxBottomSheet
import com.leantech.android.browser.dialog.DialogHelper
import com.leantech.android.browser.dialog.FontSizeBottomSheet
import com.leantech.android.browser.dialog.MenuBottomSheet
import com.leantech.android.browser.dialog.PrivacyDialog
import com.leantech.android.browser.skin.SkinManager
import com.leantech.android.browser.ui.BaseActivity
import com.leantech.android.browser.ui.InterstitialAdViewModel
import com.leantech.android.browser.ui.browser.adapter.TabPreviewAdapter
import com.leantech.android.browser.ui.browser.adapter.TabPreviewItem
import com.leantech.android.browser.ui.browser.viewmodel.BrowserTabViewModel
import com.leantech.android.browser.ui.browser.viewmodel.BrowserViewModel
import com.leantech.android.browser.ui.browser.viewmodel.ShortCutEntryViewModel
import com.leantech.android.browser.ui.favorites.FavoritesActivity
import com.leantech.android.browser.ui.search.SearchFragment
import com.leantech.android.browser.ui.setting.SettingActivity
import com.leantech.android.browser.utils.onThrottleClick
import com.leantech.android.browser.utils.show
import com.leantech.android.browser.utils.successToast
import com.leantech.android.browser.utils.toast
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import splitties.activities.start
import splitties.fragments.addToBackStack
import splitties.fragments.fragmentTransaction
import splitties.resources.str

class BrowserActivity : BaseActivity(), BrowserDelegate, TabPreviewAdapter.PreviewTabItemCallback,
    TabController, MenuBottomSheet.UserClickListener, MenuBottomSheet.MenuSettingClickListener,
    MenuBottomSheet.MenuItemListener, WorkFlows.MainFlowCallback {

    companion object {
        private const val LOG_TAG = "RocketBrowser"


        const val InternalActionSearch = "RBSearch" //search with

        const val ExtraSearchKeyword = SearchManager.QUERY //String
        const val ExtraSearchOpenNewTab = "RBOpenUrlInNewTab" //bool
        const val ExtraSearchClearHistory = "RBClearHistory"
        const val ExtraRequestLoadAd = "RBRequestLoadAd"

        const val KEY_IS_VIP = "KEY_IS_VIP"
    }

    private lateinit var binding: ActivityBrowserBinding
    private val tabViewModel by viewModel<BrowserTabViewModel>()
    private val viewModel by viewModel<BrowserViewModel>()
    private val shortCutEntryViewModel by viewModel<ShortCutEntryViewModel>()
    private val adViewModel by viewModel<InterstitialAdViewModel>()

    private val splashAdState: HotSplashAdState by inject()

    private lateinit var menuBottomSheet: MenuBottomSheet

    private var hasWebContentLoaded = false

    private var urlCollected = false

    private lateinit var permissionExplainPopup: Dialog

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityBrowserBinding.inflate(layoutInflater)
        setContentView(binding.root)

        handleIntent(intent)


        initView()

        init()

        subscribeFlow()
    }

    private fun ensureBlank() {
        if (tabViewModel.tabList.isEmpty()) {
            newTab("")
        }
    }

    private fun handleIntent(intent: Intent?) {
        LOG.d(LOG_TAG, "BrowserActivity handleIntent $intent")
        if (intent == null) return
        when (intent.action) {
            null, "" -> {
                ensureBlank()
            }

            InternalActionSearch -> {
                hideSearchFragment()
                val query = intent.getStringExtra(ExtraSearchKeyword)
                val newTab = intent.getBooleanExtra(ExtraSearchOpenNewTab, false)
                if (query.isNullOrBlank()) return
                val realUrl =
                    if (UrlUtils.isUrl(query)) query else viewModel.getCurrentSearchEngine()
                        ?.getUrl(query)
                LOG.d(LOG_TAG, "Intent Action InternalActionSearch , real url $realUrl")
                if (realUrl.isNullOrBlank()) return

                if (newTab) {
                    newTab(realUrl)
                } else {
                    val clearHistory = intent.getBooleanExtra(ExtraSearchClearHistory, false)
                    tabViewModel.getCurrentTab()?.loadUrl(realUrl, clearHistory)
                }
                val requestLoadAd = intent.getBooleanExtra(ExtraRequestLoadAd, false)
                if (requestLoadAd) {
                    adViewModel.requestLoadAd()
                }
            }

            Intent.ACTION_VIEW -> {
                val viewUri = intent.data ?: return
                val newTab = intent.getBooleanExtra(ExtraSearchOpenNewTab, false)
                if (viewUri.scheme == "http" || viewUri.scheme == "https") {
                    val realUrl = viewUri.toString()
                    if (newTab) {
                        newTab(realUrl)
                    } else {
                        val clearHistory = intent.getBooleanExtra(ExtraSearchClearHistory, false)
                        tabViewModel.getCurrentTab()?.loadUrl(realUrl, clearHistory)
                    }

                    val requestLoadAd = intent.getBooleanExtra(ExtraRequestLoadAd, false)
                    if (requestLoadAd) {
                        adViewModel.requestLoadAd()
                    }

                } else {
                    LOG.e(LOG_TAG, "can not handle intent uri $viewUri")
                }
            }
        }
    }

    @SuppressLint("MissingSuperCall")
    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        handleIntent(intent)
    }

    private fun init() {
        WorkFlows.startMainFlow(this, this)
    }

    private fun subscribeFlow() {
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.CREATED) {
                launch {
                    adViewModel.adLoadFlow.collectLatest { adState ->
                        if (adState == InterstitialAdViewModel.InterstitialAdLoadSignal.Accept) {
                            adViewModel.markAdStateLoading()
                            AdLoaders.startInterstitialAd(this@BrowserActivity, onAdShow = {
                                adViewModel.markAdStateShow()
                            }, onAdFinished = {
                                adViewModel.onAdClose()
                                splashAdState.reset()
                            })
                        }
                    }
                }

                launch {
                    tabViewModel.currentBackStackFlow.collectLatest { backStackList ->
                        val hasWebContent =
                            backStackList.size > 1 && backStackList.firstOrNull() == BrowserTab.BackStackItem.Home
                        hasWebContentLoaded = hasWebContent
                    }
                }

                launch {
                    tabViewModel.currentBackStateFlow.collectLatest {
                        binding.btnBack.isEnabled = it
                    }
                }

                launch {
                    tabViewModel.currentForwardStateFlow.collectLatest {
                        binding.btnForward.isEnabled = it
                    }
                }

                launch {
                    tabViewModel.currentFavoriteStateFlow.collectLatest {
                        urlCollected = it
                    }
                }

                launch {
                    splashAdState.hotSplashCountFlow.collectLatest { count ->
                        if (count > 0) {
                            adViewModel.requestLoadAd(false)
                        }
                    }
                }


                launch {
                    tabViewModel.tabCountFlow.collectLatest { count ->
                        val countText = when {
                            count <= 0 -> ""
                            count <= 9 -> "$count"
                            else -> "9"
                        }
                        binding.textTabCount.text = countText
                        binding.textTabMore.show(count > 9)
                        ensureBlank()
                    }
                }

                launch {
                    viewModel.lockPortraitFlow.collectLatest {
                        requestedOrientation = if (it) {
                            ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
                        } else {
                            ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
                        }
                    }
                }

                launch {
                    viewModel.privacyModeFlow.collectLatest {
                        //do nothing. 只是为了使用stateFlow，缓存value
                    }
                }

                launch {
                    combine(
                        tabViewModel.currentBackStateFlow, viewModel.showAdBlockEntryFlow
                    ) { canGoBack, showAdBlock ->
                        !canGoBack && showAdBlock //在homePage
                    }.collectLatest {
                        binding.btnRewardAd.show(it)
                    }
                }

            }
        }

    }

    private fun initView() {
        binding.btnBack.onThrottleClick {
            tabViewModel.getCurrentTab()?.back()
        }

        binding.btnForward.onThrottleClick {
            tabViewModel.getCurrentTab()?.forward()
        }

        binding.btnMenu.onThrottleClick {
            showMenu()
        }

        binding.btnTabs.onThrottleClick {
            enterPreview()
        }

        binding.btnHome.onThrottleClick {
            tabViewModel.getCurrentTab()?.home()
        }

        binding.btnRewardAd.onThrottleClick {
            AdLoaders.startRewardAd(this, onReward = {
                showBlockConfirmDialog()
            })
        }

    }

    private fun showBlockConfirmDialog() {
        DialogHelper.showVipDialog(this, R.layout.dialog_ad_block_confirm, onConfirm = { dismiss ->
            dismiss() //dismiss dialog.
            AdLoaders.startRewardAd(this, onReward = {
                successToast("广告去除成功，次日生效")
                viewModel.updateAdBlockTime()
            })

        })

    }

    private fun showMenu() {
        menuBottomSheet = BottomSheetDialogHelper.createMenuDialog(this, this, this, this)

        val webViewVisible = tabViewModel.getCurrentTab()?.webViewVisible() ?: false

        //update data.
        menuBottomSheet.apply {
            checkMenuItem(
                R.id.menu_id_lock_portrait, viewModel.currentLockPortrait()
            )
            selectMenuItem(R.id.menu_id_reader_mode, viewModel.currentReaderMode())
            selectMenuItem(
                R.id.menu_id_no_image,
                viewModel.getCurrentImageMode() != SettingConstants.DefaultImageMode
            )
            enableMenuItem(R.id.menu_id_collect, hasWebContentLoaded && webViewVisible)
            checkMenuItem(
                R.id.menu_id_collect, hasWebContentLoaded && webViewVisible && urlCollected
            )
            enableMenuItem(R.id.menu_id_refresh, hasWebContentLoaded && webViewVisible)
            enableMenuItem(R.id.menu_id_save_page, hasWebContentLoaded && webViewVisible)
            checkMenuItem(R.id.menu_id_reader_mode, viewModel.currentReaderMode())
            checkMenuItem(R.id.menu_id_privacy_mode, viewModel.currentPrivacyMode())
            val darkModeOn =
                viewModel.getCurrentDarkMode() == SettingConstants.DarkModeForceDark || (viewModel.getCurrentDarkMode() == SettingConstants.DarkModeFollowSystem && SkinManager.isSystemDarkModeOn(
                    this@BrowserActivity
                ))
            selectMenuItem(R.id.menu_id_dark_mode, darkModeOn)
            selectPage(0)

            show()
        }
    }

    override fun newTab(url: String) {
        if (tabViewModel.reachMaxSize()) {
            toast("窗口已达上限")
            return
        }

        val fragment = BrowserFragment.createInstance(url)
        fragmentTransaction(allowStateLoss = true) {
            tabViewModel.getCurrentTab()?.also {
                hide(it.getFragment())
            }

            add(R.id.tab_container, fragment)
        }

        fragment.resume()

        tabViewModel.addTab(fragment)
    }

    override fun closeTab(index: Int) {
        tabViewModel.removeTab(index)?.also {
            fragmentTransaction(allowStateLoss = true) {
                remove(it.getFragment())
                it.destroy()

                tabViewModel.getCurrentTab()?.also {
                    show(it.getFragment())
                }
            }
        }
    }

    override fun selectTab(index: Int) {
        fragmentTransaction(allowStateLoss = true) {
            tabViewModel.getCurrentTab()?.also {
                hide(it.getFragment())
                it.pause()
            }
            tabViewModel.getTabAt(index)?.also {
                show(it.getFragment())
                it.resume()
            }
        }

        tabViewModel.selectTab(index)
    }

    override fun removeAllTab() {
        fragmentTransaction(allowStateLoss = true) {
            tabViewModel.tabList.forEach {
                remove(it.getFragment())
                it.destroy()
            }
        }

        tabViewModel.removeAll()
        exitPreview()
    }

    override fun enterPreview() {
        tabViewModel.getCurrentTab()?.also { tab ->
            //截图后加入，保证不会截图到其他视图
            tab.requestCapture {
                fragmentTransaction(now = false, allowStateLoss = true) {
                    setReorderingAllowed(true)
                    addSharedElement(binding.tabContainer, binding.tabContainer.transitionName)
                    addToBackStack()
                    replace(R.id.full_fragment_container, TabPreviewFragment())
                }
            }
        }
    }

    override fun exitPreview() {
        onBackPressed()
    }

    override fun onTabItemClick(item: TabPreviewItem) {
        selectTab(item.tabIndex)
        exitPreview()
    }

    override fun onTabItemClose(item: TabPreviewItem, adapterPosition: Int) {
        closeTab(item.tabIndex)
        exitPreview()
    }

    override fun showSearchFragment(keyword: String, fromHome: Boolean) {
        fragmentTransaction(now = false, allowStateLoss = true) {
            setReorderingAllowed(true)
            addToBackStack()
            replace(R.id.full_fragment_container, SearchFragment.newInstance(keyword, fromHome))
        }
    }

    private fun hideSearchFragment() {
        supportFragmentManager.popBackStackImmediate()
    }

    override fun refresh() {
        tabViewModel.getCurrentTab()?.reload()
    }

    override fun onMenuUserClick(dialog: MenuBottomSheet) {
        dialog.dismiss()
    }

    override fun onMenuSettingClick(dialog: MenuBottomSheet) {
        dialog.dismiss()
        start<SettingActivity>()
    }

    override fun onMenuShareClick(dialog: MenuBottomSheet) {

    }

    override fun onMenuItemClick(
        dialog: MenuBottomSheet, menuItem: MenuBottomSheet.MenuItem, position: Int,
    ) {
        when (menuItem.viewId) {
            R.id.menu_id_favorites -> {
                start<FavoritesActivity>()
                dialog.dismiss()
            }

            R.id.menu_id_history -> {
                FavoritesActivity.start(this, 1)
                dialog.dismiss()
            }

            R.id.menu_id_set -> {
                start<SettingActivity>()
                dialog.dismiss()
            }

            R.id.menu_id_download -> {

            }

            R.id.menu_id_book -> {
                lifecycleScope.launch {
                    val rawText = tabViewModel.getCurrentTab()?.getRawText()
                    LOG.d("WebView", "rawText is $rawText")
                }

                dialog.dismiss()
            }

            R.id.menu_id_video -> {

            }

            R.id.menu_id_explorer -> {
                dialog.dismiss()
                launchFileExplorer()
            }

            R.id.menu_id_refresh -> {
                tabViewModel.getCurrentTab()?.reload()
                dialog.dismiss()
            }

            R.id.menu_id_exit -> {
                finish()
            }

            R.id.menu_id_dark_mode -> {
                val darkMode = viewModel.getCurrentDarkMode()
                BottomSheetDialogHelper.createDarkModeDialog(
                    this, darkMode
                ) { d, newDarkMode ->
                    viewModel.updateDarkMode(newDarkMode)
                    d.dismiss()
                }.show()

                dialog.dismiss()
            }

            R.id.menu_id_no_image -> {
                val imgMode = viewModel.getCurrentImageMode()
                //show image
                if (imgMode == SettingConstants.DefaultImageMode) {
                    BottomSheetDialogHelper.createImageModeDialog(
                        this, imgMode
                    ) { d, newImageMode ->
                        viewModel.updateImageMode(newImageMode)
                        toast("已开启无图模式")
                        d.dismiss()
                    }.show()
                } else {
                    viewModel.updateImageMode(SettingConstants.DefaultImageMode)
                    toast("已关闭无图模式")
                }

                dialog.dismiss()
            }

            R.id.menu_id_translate -> {

            }

            R.id.menu_id_clear_cache -> {
                showClearCacheDialog()
                dialog.dismiss()
            }

            R.id.menu_id_ua_setting -> {
                BottomSheetDialogHelper.createUASettingDialog(
                    this,
                    viewModel.userAgentList(),
                    onItemClick = { ua ->
                        if (ua != null) {
                            viewModel.switchUserAgent(ua.id)
                            toast("UA已切换到【${ua.name}】")
                        }
                    }).show()

                dialog.dismiss()
            }

            R.id.menu_id_page_find -> {

            }

            R.id.menu_id_color_pick -> {

            }

            R.id.menu_id_screenshot -> {

            }

            R.id.menu_id_save_page -> {

            }

            R.id.menu_id_font -> {
                FontSizeBottomSheet(this) { fontSize ->
                    LOG.d(LOG_TAG, "font size update to $fontSize")
                    viewModel.updateFontSize(fontSize)
                }.apply {
                    updateProgress(viewModel.getCurrentFontSize())
                    show()
                }

                dialog.dismiss()
            }

            R.id.menu_id_report -> {

            }

            R.id.menu_id_windows -> {
                enterPreview()
                dialog.dismiss()
            }
        }
    }

    private fun launchFileExplorer() {


    }

    private fun showClearCacheDialog() {
        CheckboxBottomSheet.Builder(this).setTitle(str(R.string.menu_item_clear_cache))
            .addItem(str(R.string.text_clear_history), false, R.id.action_clear_history)
            .addItem(str(R.string.text_clear_storage), false, R.id.action_clear_storage)
//            .addItem(str(R.string.text_clear_account), false, R.id.action_clear_account)
            .addItem(str(R.string.text_clear_cookie), false, R.id.action_clear_cookie)
            .addItem(str(R.string.text_clear_form), false, R.id.action_clear_form)
            .addItem(str(R.string.text_clear_geo), false, R.id.action_clear_geo_permission)
            .setOnItemChecked { dialog, items ->
                if (items.isEmpty()) {
                    toast("请选择清理项")
                } else {
                    items.forEach {
                        when (it.tag) {
                            R.id.action_clear_history -> {
                                viewModel.clearHistory()
                            }

                            R.id.action_clear_storage -> {
                                WebStorage.getInstance().deleteAllData()
                            }

                            R.id.action_clear_account -> {
                                WebViewDatabase.getInstance(this).clearHttpAuthUsernamePassword()
                                WebViewDatabase.getInstance(this).clearUsernamePassword()
                            }

                            R.id.action_clear_cookie -> {
                                CookieManager.getInstance().removeAllCookies(null)
                            }

                            R.id.action_clear_form -> {
                                WebViewDatabase.getInstance(this).clearFormData()
                                viewModel.clearSearchHistory()
                            }

                            R.id.action_clear_geo_permission -> {
                                GeolocationPermissions.getInstance().clearAll()
                            }
                        }
                    }

                    toast("已清除")
                    dialog.dismiss()
                }


            }.build().show()
    }

    @SuppressLint("SourceLockedOrientationActivity")
    override fun onMenuItemCheckChanged(
        dialog: MenuBottomSheet,
        menuItem: MenuBottomSheet.MenuItem,
        position: Int,
        checked: Boolean,
    ) {
        when (menuItem.viewId) {
            R.id.menu_id_reader_mode -> {
                viewModel.updateReaderMode(checked)
                tabViewModel.getCurrentTab()?.enableReaderMode(checked)
                dialog.dismiss()
            }

            R.id.menu_id_collect -> {
                tabViewModel.getCurrentTab()?.toggleFavorite()
                dialog.dismiss()
            }

            R.id.menu_id_dark_mode -> {

                dialog.dismiss()
            }

            R.id.menu_id_page_join -> {

            }

            R.id.menu_id_fullscreen -> {

            }

            R.id.menu_id_privacy_mode -> {
                viewModel.switchPrivacyMode(checked)
                if (checked) {
                    toast("已开启无痕浏览")
                } else {
                    toast("已关闭无痕浏览")
                }
                dialog.dismiss()
            }

            R.id.menu_id_lock_portrait -> {
                viewModel.switchLockPortrait(checked)
                if (checked) {
                    toast("已开启竖屏锁定")
                } else {
                    toast("已关闭竖屏锁定")
                }
                dialog.dismiss()
            }

        }
    }

    override fun doOnBackPressed() {
        val backStackCount = supportFragmentManager.backStackEntryCount
        if (backStackCount > 0) {
            super.doOnBackPressed()
        } else {
            tabViewModel.getCurrentTab()?.back()
        }
    }

    override fun showPrivacyDialog(chain: PrivacyDialogBlockChain) {
        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        PrivacyDialog(this, false, {
            chain.onAccept {
                requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
            }
        }, {
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
            chain.onDenied()
        }).show()
    }

    override fun showVipDialog(chain: VipDialogBlockChain) {
        DialogHelper.showVipDialog(this, R.layout.dialog_vip_cbrowser, onConfirm = { afterCall ->
            chain.onAccept({
                afterCall()
                successToast("领取成功")
            }, true)

        }, onCancel = {
            chain.onDenied()
        })
    }
}